package old_Core;

import MathCore.Real;
import java.util.*;

public class AlternateCore
{

	private Stack operands = new Stack();
	private Vector exit = new Vector();
	private Stack stack = new Stack();
	public Hashtable vars = new Hashtable();
	private StkElem el,  elem,  s3;
	private Real h1,  h2,  h3;
	private Real toD = new Real(180);
	private Real h4 = new Real();
	public Vector fullBufer = new Vector();
	public Real bufer = new Real();
	public Real x_var = new Real(0),  x_bufer = new Real();
	public Real otv = new Real();
	private Vector universalArr = new Vector();
	private Vector subArr;
	private Vector upperArr;
	private int maxDeep = 0;
	private int nowDeep = 0;
	public final static int ANGLE_DEGREE = 0,  ANGLE_GRAD = 2,  ANGLE_RADIAN = 1;
	public int angleType = ANGLE_RADIAN;
	private static String funcList[] =
	{
		"sin", "cos", "tan", "ctg", "arcsin", "arccos", "arctg", "arcctg", "det", "sqrt", "fact", "ln", "log", "abs", "d"
	};
	private static String operList[] =
	{
		"+", "-", "*", "/", "^"
	};

	// Конструктор
	public AlternateCore()
	{
		for (int i = 0; i < 100; i++)
		{
			fullBufer.addElement(new StkElem());
		}
	}

	// Добавление переменной
	public void addVar(String s, Real r)
	{
		vars.put(s, new Real(r));
	}

	// Добавление переменной, перегруженное абсолютно для любого обьекта
	public void addVar(String s, Object var)
	{
		vars.put(s, var);
	}

	// Преобразование параметра-угла к радианам
	private void processAngleTo(Real var)
	{
		if (angleType == ANGLE_DEGREE)
		{
			var.mul(Real.PI);
			var.div(180);
		} else if (angleType == ANGLE_GRAD)
		{
			var.mul(Real.PI);
			var.div(200);
		} else
		{
			angleType = ANGLE_RADIAN;
		}

	}

	// Преобразование результата обратной триг. ф-ии к требуемому углу
	private void processAngleFrom(Real var)
	{
		if (angleType == ANGLE_DEGREE)
		{
			var.div(Real.PI);
			var.mul(180);
		} else if (angleType == ANGLE_GRAD)
		{
			var.div(Real.PI);
			var.mul(200);
		} else
		{
			angleType = ANGLE_RADIAN;
		}
	}

	public void setVar(String s, Object var)
	{
		Object o = vars.get(s);

		if (((o instanceof Real) && (var instanceof Matrix)) || ((o instanceof Matrix) && (var instanceof Real)))
		{
			vars.remove(s);
			addVar(s, var);
		} else
		{
			if (o instanceof Real)
			{
				((Real) o).assign((Real) var);
			} else if (o instanceof Matrix)
			{
				((Matrix) o).set((Matrix) var);
			}
		}
	}

	public Object getVar(String s)
	{
		return vars.get(s);
	}

	public void reset()
	{
		if (!operands.isEmpty())
		{
			operands.removeAllElements();
		}
		if (!exit.isEmpty())
		{
			exit.removeAllElements();
		}
		if (!stack.isEmpty())
		{
			stack.removeAllElements();
		}
		h1 = Real.ZERO;
	}

	private int getPriority(StkElem e)
	{
		if (e.type == 'f')
		{
			return 19;
		}
		if (e.s.equals("+") || e.s.equals("-"))
		{
			return 16;
		}
		if (e.s.equals("*") || e.s.equals("/"))
		{
			return 17;
		}
		if (e.s.equals("^"))
		{
			return 18;
		}
		return 0;
	}

	public Vector normalToRPN(Vector inp) throws SortException
	{
		Vector exit = new Vector();

		int fs = 0, os = 0;
		for (int i = 0; i < inp.size(); i++)
		{
			if (((StkElem) inp.elementAt(i)).type == '(')
			{
				os++;
			}
			if (((StkElem) inp.elementAt(i)).type == ')')
			{
				os--;
			}

			if (((StkElem) inp.elementAt(i)).type == '{')
			{
				fs++;
			}
			if (((StkElem) inp.elementAt(i)).type == '}')
			{
				fs--;
			}
		}

		if (fs != 0 || os != 0)
		{
			throw new SortException("Дисбаланс скобок в выражении");
		}

		for (int i = 0; i < inp.size(); i++)
		{
			elem = (StkElem) inp.elementAt(i);

			if (elem.type == 'n' || elem.type == 'm' || elem.type == 'd' || elem.type == 'c')
			{
				exit.addElement(elem);
			} else if (elem.type == 'v')
			{
				if (getVar(elem.s) != null)
				{
					if (getVar(elem.s) instanceof Real)
					{
						exit.addElement(new StkElem((Real) getVar(elem.s)));
					}
					if (getVar(elem.s) instanceof Matrix)
					{
						exit.addElement(new StkElem((Matrix) getVar(elem.s)));
					}
				} else
				{
					throw new SortException("Переменная '" + elem.s + "' не определена ");
				}

			} else if (elem.type == 'f')
			{
				stack.push(elem);
			} else if (elem.s.equals(","))
			{
				StkElem e;
				while (true)
				{
					try
					{
						e = (StkElem) stack.pop();
					} catch (EmptyStackException except)
					{
						throw new SortException("Несогласовано использование запятой");
					}
					if (e.type == '{' || e.type == '(')
					{
						stack.push(e);
						break;
					}
					exit.addElement(e);
				}
			} else if (elem.type == 'o')
			{
				if (!stack.empty())
				{
					while (true)
					{
						if (stack.empty())
						{
							break;
						}
						if (getPriority(elem) > getPriority((StkElem) stack.lastElement()))
						{
							break;
						}
						exit.addElement(stack.pop());
					}
				}
				stack.push(elem);

			} else if (elem.type == '(')
			{
				stack.push(elem);

			} else if (elem.type == '{')
			{
				stack.push(elem);
				exit.addElement(elem);

			} else if (elem.type == '}')
			{
				try
				{
					if (!stack.empty())
					{
						el = (StkElem) stack.lastElement();
						while (!stack.empty())
						{
							el = (StkElem) stack.lastElement();
							if (el.type == '{')
							{
								stack.pop();
								break;
							}
							exit.addElement((StkElem) stack.pop());

							el = (StkElem) stack.lastElement();
						}
					}
					exit.addElement(elem);
				} catch (Exception e)
				{
					throw new SortException("Дисбаланс скобок в выражении");
				}

			} else if (elem.type == ')')
			{
				try
				{
					if (!stack.empty())
					{
						el = (StkElem) stack.lastElement();
						while (!stack.empty())
						{
							el = (StkElem) stack.lastElement();
							if (el.type == '(')
							{
								stack.pop();
								break;
							}
							exit.addElement((StkElem) stack.pop());
							el = (StkElem) stack.lastElement();
						}
					}
				} catch (Exception e)
				{
					throw new SortException("Дисбаланс скобок в выражении");
				}
			}
		}

		while (!stack.empty())
		{
			exit.addElement((StkElem) stack.pop());
		}

		String input = "";
		StkElem e;


		for (int j = 0; j < exit.size(); j++)
		{
			e = (StkElem) exit.elementAt(j);

			if (e.type == 'n')
			{
				input += e.r.toString();
			} else if (e.type == 'm')
			{
				input += e.matrix.toString();
			} else
			{
				input += e.s;
			}

			input += " ";
		}
		//System.out.println(input);


		return exit;

	}

	public StkElem solve(Vector inp) throws SolveException
	{
		x_bufer.assign(x_var);
		for (int i = 0; i < inp.size(); i++)
		{
			StkElem e = (StkElem) fullBufer.elementAt(i);
			e.set((StkElem) inp.elementAt(i));
		}

		for (int i = 0; i < inp.size(); i++)
		{
			el = (StkElem) fullBufer.elementAt(i);

			if (el.type == 'n')
			{
				operands.push(el.r);
			} else if (el.type == 'm')
			{
				operands.push(el.matrix);
			} else if (el.type == 'v')
			{
				operands.push(getVar(el.s));
			} else if (el.type == 'c')
			{
				if (el.s.equals("π"))
				{
					operands.push(new Real(Real.PI));
				}
				if (el.s.equals("inf"))
				{
					operands.push(new Real(Real.INF));
				}
				if (el.s.equals("-inf"))
				{
					operands.push(new Real(Real.INF_N));
				}
			} else if (el.type == '{')
			{
				operands.push(el);

				if (nowDeep == 0)
				{
					subArr = universalArr;
				} else
				{
					subArr.addElement(new Vector());
					upperArr = subArr;
					subArr = (Vector) subArr.lastElement();
				}
				nowDeep++;
				if (maxDeep < nowDeep)
				{
					maxDeep = nowDeep;
				}
			} else if (el.type == '}')
			{
				Object o;
				while (true)
				{
					o = operands.pop();
					if (o instanceof StkElem)
					{
						nowDeep--;
						if (nowDeep == 0)
						{
							if (maxDeep == 2)
							{
								Matrix m = new Matrix(universalArr);
								operands.push(m);
							//System.out.println("Matrix compiled: ");
							//System.out.println(m.toString());
							} else if (maxDeep == 1)
							{
								Vector row = new Vector();
								row.addElement(universalArr);
								Matrix m = new Matrix(row);
								operands.push(m);
							//System.out.println("Matrix compiled: ");
							//System.out.println(m.toString());
							} else
							{
								throw new SolveException("Трех- и более- мерные массивы пока не поддерживаются.");
							}
							universalArr.removeAllElements();
							maxDeep = nowDeep = 0;
							upperArr = null;
						} else
						{
							subArr = upperArr;
						}
						break;
					} else
					{
						subArr.addElement(o);
					}
				}
			} else
			{
				if (el.s.equals("+"))
				{
					try
					{
						h1 = (Real) operands.pop();
						h1.add((Real) operands.pop());
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно операндов у оператора '" + el.s + "'");
					}
					operands.push(h1);

				} else if (el.s.equals("-") && el.type == 'o')
				{
					try
					{
						h1 = (Real) operands.pop();
						h1.sub((Real) operands.pop());
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно операндов у оператора '" + el.s + "'");
					}
					h1.neg();
					operands.push(h1);

				} else if (el.s.equals("-") && el.type == 'f')
				{
					try
					{
						h1 = (Real) operands.pop();
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно параметров у функции '" + el.s + "'");
					}
					h1.neg();
					operands.push(h1);

				} else if (el.s.equals("*"))
				{
					try
					{
						h1 = (Real) operands.pop();
						h1.mul((Real) operands.pop());
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно операндов у оператора '" + el.s + "'");
					}
					operands.push(h1);

				} else if (el.s.equals("/"))
				{
					try
					{
						h1 = (Real) operands.pop();
						h1.rdiv((Real) operands.pop());
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно операндов у оператора '" + el.s + "'");
					}
					operands.push(h1);

				} else if (el.s.equals("^"))
				{
					try
					{
						h1 = (Real) operands.pop();
						h2 = (Real) operands.pop();
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно операндов у оператора '" + el.s + "'");
					}
					h2.pow(h1);
					operands.push(h2);

				} else if (el.s.equals("sin"))
				{
					try
					{
						h1 = (Real) operands.pop();
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно параметров у функции '" + el.s + "'");
					}
					processAngleTo(h1);
					h1.sin();
					operands.push(h1);

				} else if (el.s.equals("det"))
				{
					Matrix m;
					try
					{
						m = (Matrix) operands.pop();
						operands.push(m.det());
					} catch (Exception e)
					{
						throw new SolveException("Параметр функции det - не матрица");
					}

				} else if (el.s.equals("cos"))
				{
					try
					{
						h1 = (Real) operands.pop();
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно параметров у функции '" + el.s + "'");
					}
					processAngleTo(h1);
					h1.cos();
					operands.push(h1);

				} else if (el.s.equals("tan") || el.s.equals("tg"))
				{
					try
					{
						h1 = (Real) operands.pop();
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно параметров у функции '" + el.s + "'");
					}
					processAngleTo(h1);
					h1.tan();
					operands.push(h1);

				} else if (el.s.equals("ctg"))
				{
					try
					{
						h1 = (Real) operands.pop();
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно параметров у функции '" + el.s + "'");
					}
					processAngleTo(h1);
					h1.tan();
					h1.rdiv(Real.ONE);
					operands.push(h1);

				} else if (el.s.equals("asin"))
				{
					try
					{
						h1 = (Real) operands.pop();
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно параметров у функции '" + el.s + "'");
					}
					h1.asin();
					processAngleFrom(h1);
					operands.push(h1);

				} else if (el.s.equals("acos"))
				{
					try
					{
						h1 = (Real) operands.pop();
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно параметров у функции '" + el.s + "'");
					}
					h1.acos();
					processAngleFrom(h1);
					operands.push(h1);

				} else if (el.s.equals("atg"))
				{
					try
					{
						h1 = (Real) operands.pop();
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно параметров у функции '" + el.s + "'");
					}
					h1.atan();
					processAngleFrom(h1);
					operands.push(h1);

				} else if (el.s.equals("actg"))
				{
					try
					{
						h1 = (Real) operands.pop();
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно параметров у функции '" + el.s + "'");
					}
					h1.atan();
					h1.rdiv(1);
					processAngleFrom(h1);
					operands.push(h1);

				} else if (el.s.equals("sqrt"))
				{
					try
					{
						h1 = (Real) operands.pop();
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно параметров у функции '" + el.s + "'");
					}
					h1.sqrt();
					operands.push(h1);

				} else if (el.s.equals("fact"))
				{
					try
					{
						h1 = (Real) operands.pop();
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно параметров у функции '" + el.s + "'");
					}
					if (h1.greaterEqual(0))
					{
						h1.fact();
					} else
					{
						h1.assign(0);
					}
					operands.push(h1);


				} else if (el.s.equals("abs"))
				{
					try
					{
						h1 = (Real) operands.pop();
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно параметров у функции '" + el.s + "'");
					}
					h1.abs();
					operands.push(h1);

				} else if (el.s.equals("ln"))
				{
					try
					{
						h1 = (Real) operands.pop();
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно параметров у функции '" + el.s + "'");
					}
					h1.ln();
					operands.push(h1);

				} else if (el.s.equals("log"))
				{
					try
					{
						h1 = (Real) operands.pop();
						h2 = (Real) operands.pop();
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно параметров у функции '" + el.s + "'");
					}
					h1.log2();
					h2.log2();
					h1.div(h2);
					operands.push(h1);

				} else if (el.s.equals("d"))
				{
					try
					{
						h1 = (Real) operands.pop();
					} catch (Exception e)
					{
						throw new SolveException("Недостаточно параметров у функции '" + el.s + "'");
					}
					h1.div(toD);
					h1.mul(Real.PI);
					operands.push(h1);

				} else if (el.s.equals("x"))
				{
					operands.push(new Real(x_var));

				} else if (el.s.equals("d"))
				{
					operands.push(new Real(x_var));
				}
			}
		}

		Object resultElement;
		if (!operands.empty())
		{
			resultElement = operands.pop();
		} else
		{
			resultElement = new Real(Real.NAN);
		}

		if (!operands.empty())
		{
			operands.removeAllElements();
		}
		if (bufer != null && s3 != null)
		{
			s3.r.assign(bufer);
		}
		x_var.assign(x_bufer);

		if (resultElement instanceof Real)
		{
			return new StkElem((Real) resultElement);
		}
		else if (resultElement instanceof Matrix)
		{
			return new StkElem((Matrix) resultElement);
		}

		return null;
	}
}

// конец